﻿using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using Zo.Events.Core;
using Zo.Common;

namespace Zo.Events
{
    /// <summary>
    /// 事件处理器。
    /// </summary>
    public interface IEventManager
    {
        /// <summary>
        /// 注册事件处理器。
        /// </summary>
        /// <param name="eventHandler">事件处理器。</param>
        void Register(IEventHandler eventHandler);

        /// <summary>
        /// 事件处理。
        /// </summary>
        /// <param name="name">事件名。</param>
        /// <param name="envelope">事件信息。</param>
        void Handle(string name, object envelope);

        /// <summary>
        /// 事件处理。
        /// </summary>
        /// <param name="name">事件名。</param>
        /// <param name="envelope">事件信息。</param>
        /// <returns>事件结果。</returns>
        Task<IEventResult> HandleAsync(string name, object envelope);
    }

    /// <summary>
    /// 默认事件处理器。
    /// </summary>
    internal class DefaultEventManager : IEventManager
    {
        /// <summary>
        /// 事件执行者集合。
        /// </summary>
        private readonly IDictionary<string, IEventExecutor> _eventExecutors = new ConcurrentDictionary<string, IEventExecutor>();

        /// <summary>
        /// 注册事件处理器。
        /// </summary>
        /// <param name="eventHandler">事件处理器。</param>
        public void Register(IEventHandler eventHandler)
        {
            Check.NotNull(eventHandler, nameof(eventHandler));

            var name = eventHandler.Name ?? string.Empty;

            name = name.ToLower();

            Check.NotEmpty(name, nameof(name));

            _eventExecutors[name] = new DefaultEventExecutor(name, eventHandler);
        }

        /// <summary>
        /// 事件处理。
        /// </summary>
        /// <param name="name">事件名。</param>
        /// <param name="envelope">事件信息。</param>
        public void Handle(string name, object envelope)
        {
            Check.NotEmpty(name, nameof(name));
            Check.NotNull(envelope, nameof(envelope));

            name = name.ToLower();

            _eventExecutors[name].Handle(envelope);
        }

        /// <summary>
        /// 事件处理。
        /// </summary>
        /// <param name="name">事件名。</param>
        /// <param name="envelope">事件信息。</param>
        /// <returns>事件结果。</returns>
        public Task<IEventResult> HandleAsync(string name, object envelope)
        {
            Check.NotEmpty(name, nameof(name));
            Check.NotNull(envelope, nameof(envelope));

            name = name.ToLower();

            return _eventExecutors[name].HandleAsync(envelope);
        }
    }
}